package com.daichi.controller;


import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.daichi.common.dto.PassDto;
import com.daichi.common.lang.Const;
import com.daichi.common.lang.Result;
import com.daichi.entity.SysRole;
import com.daichi.entity.SysUser;
import com.daichi.entity.SysUserRole;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.security.Principal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author Daichi Chou
 * @since 2021-06-05
 */
@RestController
@RequestMapping("/sys/user")
public class SysUserController extends BaseController {

    private final BCryptPasswordEncoder passwordEncoder;

    @Autowired
    public SysUserController(BCryptPasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }

    @GetMapping("/info/{id}")
    @PreAuthorize("hasAuthority('sys:user:list')")
    public Result info(@PathVariable Long id) {
        SysUser sysUser = sysUserService.getById(id);
        Assert.notNull(sysUser, "用户不存在");
        List<SysRole> sysRoles = sysUserRoleService.listRolesByUserId(id);

        sysUser.setSysRoles(sysRoles);
        return Result.succ(sysUser);
    }

    @GetMapping("/list")
    @PreAuthorize("hasAuthority('sys:user:list')")
    public Result list(String username) {

        Page<SysUser> page = sysUserService.page(getPage(), new QueryWrapper<SysUser>().like(StrUtil.isNotBlank(username), "username", username));

        page.getRecords().forEach(user -> {
            List<SysRole> sysRoles = sysUserRoleService.listRolesByUserId(user.getId());
            user.setSysRoles(sysRoles);
        });

        return Result.succ(page);
    }

    @PostMapping("/save")
    @PreAuthorize("hasAuthority('sys:user:save')")
    public Result save(@Validated @RequestBody SysUser sysUser) {

        int count = sysUserService.count(new QueryWrapper<SysUser>().eq("username", sysUser.getUsername()));
        if (count > 0) {
            return Result.fail("用户名已存在");
        }

        sysUser.setCreated(new Date());
        sysUser.setPassword(passwordEncoder.encode(Const.INIT_PASSWORD));
        sysUser.setAvatar(Const.INIT_AVATAR);

        sysUserService.save(sysUser);
        return Result.succ(sysUser);
    }

    @PostMapping("/update")
    @PreAuthorize("hasAuthority('sys:user:update')")
    public Result update(@Validated @RequestBody SysUser sysUser) {

        int count = sysUserService.count(new QueryWrapper<SysUser>().eq("username", sysUser.getUsername()));
        if (count > 0) {
            return Result.fail("用户名已存在");
        }

        sysUser.setUpdated(new Date());
        sysUserService.updateById(sysUser);
        return Result.succ(sysUser);
    }

    @PostMapping("/delete")
    @PreAuthorize("hasAuthority('sys:user:delete')")
    @Transactional(rollbackFor = Exception.class)
    public Result delete(@RequestBody List<Long> ids, Principal principal) {

        List<SysUser> sysUsers = sysUserService.listByIds(ids);
        List<String> usernameList = new ArrayList<>();
        for (SysUser user : sysUsers) {
            if (user.getUsername().equals(principal.getName())) {
                return Result.fail("不能删除本用户");
            }
            usernameList.add(user.getUsername());
        }

        sysUserRoleService.remove(new QueryWrapper<SysUserRole>().in("user_id", ids));
        sysUserService.removeByIds(ids);

        usernameList.forEach(u -> sysUserService.clearUserInfo(u));

        return Result.succ(null);
    }

    @PostMapping("/role/{userId}")
    @PreAuthorize("hasAuthority('sys:user:role')")
    @Transactional(rollbackFor = Exception.class)
    public Result rolePerms(@PathVariable("userId") Long userId, @RequestBody List<Long> roleIds) {

        List<SysUserRole> sysUserRoles = new ArrayList<>();

        roleIds.forEach(r -> {
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setRoleId(r);
            sysUserRole.setUserId(userId);

            sysUserRoles.add(sysUserRole);
        });
        sysUserRoleService.remove(new QueryWrapper<SysUserRole>().eq("user_id", userId));
        sysUserRoleService.saveBatch(sysUserRoles);

        SysUser sysUser = sysUserService.getById(userId);

        sysUserService.clearUserAuthorityInfo(sysUser.getUsername());

        return Result.succ(null);
    }

    @PostMapping("/repass")
    @PreAuthorize("hasAuthority('sys:user:repass')")
    public Result repass(@RequestBody Long id) {
        SysUser sysUser = sysUserService.getById(id);
        Assert.notNull(sysUser, "用户不存在");
        sysUser.setUpdated(new Date());
        sysUser.setPassword(passwordEncoder.encode(Const.INIT_PASSWORD));

        sysUserService.updateById(sysUser);
        return Result.succ(null);
    }

    @PostMapping("/updatePass")
    public Result updatePass(@Validated @RequestBody PassDto passDto, Principal principal) {

        SysUser sysUser = sysUserService.getUserByName(principal.getName());
        boolean matches = passwordEncoder.matches(passDto.getCurrentPass(), sysUser.getPassword());
        if (!matches) {
            return Result.fail("旧密码错误");
        }

        sysUser.setPassword(passwordEncoder.encode(passDto.getPassword()));
        sysUser.setUpdated(new Date());

        sysUserService.updateById(sysUser);

        sysUserService.clearUserAuthorityInfo(sysUser.getUsername());
        sysUserService.clearUserInfo(sysUser.getUsername());

        return Result.succ("");
    }

}
